package com.hliushi.demo.filter;

import lombok.extern.slf4j.Slf4j;
import org.owasp.validator.html.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author llhuang10
 * @date 2021/8/24 17:15
 */
@Slf4j
public class XssRequestWrapper extends HttpServletRequestWrapper {

    // 获的antisamy框架所需的决策文件路径
    private static String antisamyPath = XssRequestWrapper.class.getClassLoader().getResource("antisamy-test.xml").getFile();
    private static Policy policy = null;

    static {
        try {
            // 过滤策略对象
            policy = Policy.getInstance(antisamyPath);
        } catch (PolicyException e) {
            log.info("inputParams: {} and errorMessage: {}", antisamyPath, e.getMessage(), e);
        }
    }

    public XssRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    /**
     * 表单上的请求参数, 都会经过这个方法一遍
     *
     * @param name 每个表单项中的 key
     * @return 每个表单项中的 key 对应的value[]
     */
    @Override
    public String[] getParameterValues(String name) {
        String[] parameterValues = super.getParameterValues(name);
        log.info("cleanBefore   {} = {}", name, Arrays.toString(parameterValues));

        AtomicInteger index = new AtomicInteger(-1);
        String[] result = new String[parameterValues.length];
        /**
         * bug点, 这样使用函数式编程, parameterValues数组里面的数据没有发生改变
         */
        // Arrays.stream(parameterValues)
        //         .forEach(item -> item = this.cleanXss(item));
        Arrays.stream(parameterValues)
                .forEach(item -> result[index.incrementAndGet()] = this.cleanXss(item));
        log.info("cleanAfter  {} = {}", name, Arrays.toString(result));
        return result;
    }


    /**
     * 通过AntiSamy框架过滤字符
     *
     * @param text 过滤前的text
     * @return 过滤后的text
     */
    private String cleanXss(String text) {
        AntiSamy antiSamy = new AntiSamy();
        try {
            CleanResults cleanResults = antiSamy.scan(text, policy);
            text = cleanResults.getCleanHTML();
        } catch (ScanException | PolicyException e) {
            log.info("ex: {}", e.getMessage(), e);
        }
        return text;
    }
}
